home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 6 / develop 6 code / TCP / NewsWatcher / NewsWatcher 2.0d15 source / source / datetime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-29  |  5.1 KB  |  219 lines  |  [TEXT/KAHL]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     datetime.c
  4.  
  5.     This module converts RFC822 date/time lines into Mac-format date/time
  6.     strings in local time.
  7.     
  8.     Portions copyright © 1990, Apple Computer.
  9.     Portions copyright © 1993, Northwestern University.
  10.  
  11. ----------------------------------------------------------------------------*/
  12.  
  13. #include <Script.h>
  14. #include <Packages.h>
  15.  
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <stdio.h>
  19. #include <ctype.h>
  20.  
  21. #include "datetime.h"
  22. #include "util.h"
  23.  
  24.  
  25.  
  26. /*----------------------------------------------------------------------------
  27.     ParseNum
  28.     
  29.     Extract a long integer from a string.
  30.     
  31.     Entry:    *str = string.
  32.     
  33.     Exit:    function result = parsed number, or 0 if error.
  34.             *str = pointer to first non-space character following parsed nubmer.
  35.     
  36.     A POINTER to a char* is passed in; it is adjusted to point to the
  37.     next "word" after the number (skipping white space)
  38.  
  39.     Returns the number that was found, or 0.
  40. ----------------------------------------------------------------------------*/
  41.  
  42. static long ParseNum (char **str)
  43. {
  44.     long temp = 0;
  45.     char *s = *str;
  46.     
  47.     while (*s && isdigit(*s))
  48.         temp = temp * 10 + (*s++ - '0');
  49.     while (*s && isspace(*s)) s++;
  50.     *str = s;
  51.     return temp;
  52. }
  53.  
  54.  
  55.  
  56. /*----------------------------------------------------------------------------
  57.     FindMonth
  58.  
  59.     Given a string that might be a month abbreviation, return the number
  60.     of the month (starting with January = 1, ...).
  61.     
  62.     Entry:    str = month string.
  63.     
  64.     Exit:    function result = month ordinal, or 0 if can't parse.
  65.  
  66.     This isn't WorldScript-friendly, but it doesn't matter, since this
  67.     function is only used for parsing RFC822 dates
  68. ----------------------------------------------------------------------------*/
  69.  
  70. static short FindMonth (const char *str)
  71. {
  72.     static const char *months[12] = {
  73.         "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
  74.         "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
  75.     };
  76.     short i;
  77.     
  78.     for (i = 0; i < 12; i++) {
  79.         if (strcasecmp(str, months[i]) == 0) return i+1;
  80.     }
  81.     return 0;
  82. }
  83.  
  84.  
  85.  
  86. /*----------------------------------------------------------------------------
  87.     Parse822Date
  88.  
  89.     Parse a date/time that's in RFC822 header format:
  90.     
  91.     [Day, ] dd mmm [yy]yy hh:mm:ss [ GMT | (+|-) hhmm ]
  92.     
  93.     Entry:    date = RFC822 date/time string.
  94.     
  95.     Exit:    function result = number of seconds since January 1, 1904, 
  96.                 the standard Mac date convention.
  97.             function result = 0 if the date could not be parsed
  98. ----------------------------------------------------------------------------*/
  99.  
  100. unsigned long Parse822Date (char *date)
  101. {
  102.     DateTimeRec dt;
  103.     unsigned long result;
  104.     char chunk[20];
  105.     char *s, *p;
  106.     short sign;
  107.     long tzDelta;
  108.  
  109.     memset(&dt, 0, sizeof(dt));
  110.  
  111.     s = date;
  112.     if (p = strchr(date, ',')) s = p+1;        /* Skip day of week */
  113.  
  114.     while (*s && isspace(*s)) s++;            /* dd */
  115.     dt.day = ParseNum(&s);
  116.  
  117.     p = chunk;                                /* mmm */
  118.     while (*s && isalnum(*s) && p - chunk < sizeof(chunk)-1) *p++ = *s++;
  119.     *p = 0;
  120.     dt.month = FindMonth(chunk);
  121.  
  122.     while (*s && isspace(*s)) s++;            /* [yy]yy */
  123.     dt.year = ParseNum(&s);
  124.     if (dt.year < 21) {
  125.         dt.year += 2000;
  126.     } else if (dt.year < 100) {
  127.         dt.year += 1900;
  128.     }
  129.  
  130.     dt.hour = ParseNum(&s);                    /* hh */
  131.     if (*s == ':') {
  132.         s++;
  133.         dt.minute = ParseNum(&s);            /* mm */
  134.     }
  135.     if (*s == ':') {
  136.         s++;
  137.         dt.second = ParseNum(&s);            /* ss */
  138.     } else {
  139.         return 0;
  140.     }
  141.     
  142.     if (strcasecmp(s, "GMT") == 0) {        /* GMT */
  143.         s += 3;
  144.         while (*s && isspace(*s)) s++;
  145.     }
  146.  
  147.     if ((*s == '-' || *s == '+') && isdigit(*(s+1)) ) {        /* (+|-) hhmm */
  148.         if (*s == '-') {
  149.             /* If the delta is negative, we have to ADD time to get GMT */
  150.             sign = 1;
  151.         } else {
  152.             sign = -1;
  153.         }
  154.         s++;
  155.         tzDelta = ParseNum(&s);
  156.         dt.hour   += sign * (tzDelta / 100);        /* Hours */
  157.         dt.minute += sign * (tzDelta % 100);        /* Minutes */
  158.     }
  159.     
  160.     if (*s != 0) return 0;
  161.  
  162.     /* Convert to seconds since 1/1/1904 */
  163.     
  164.     Date2Secs(&dt, &result);
  165.     return result;
  166. }
  167.  
  168.  
  169. /*----------------------------------------------------------------------------
  170.     Cleanup822Date
  171.     
  172.     Converts an RFC822 date/time string into a Mac-style date/time string
  173.     in local time.
  174.     
  175.     Entry:    date = RFC822 date/time string.
  176.             
  177.     Exit:    date = Mac-style date/time string.
  178.     
  179.     If the string cannot be parsed or converted, or if the Map control
  180.     panel is not installed, the string is unchanged.
  181. ----------------------------------------------------------------------------*/
  182.  
  183. void Cleanup822Date (char *date)
  184. {
  185.     MachineLocation    loc;    /* Location info for this machine */
  186.     long gmtOffset;            /* Offset from GMT, in seconds */
  187.     unsigned long secs;
  188.     char *s, *p;
  189.     Str255 time;
  190.  
  191.     /* Get our location. Return if Map control panel not installed. */
  192.     
  193.     ReadLocation(&loc);
  194.     if (loc.latitude == 0 && loc.longitude == 0 && loc.gmtFlags.gmtDelta == 0) return;
  195.  
  196.     /* Get our offset in seconds from GMT. */
  197.     
  198.     gmtOffset = loc.gmtFlags.gmtDelta & 0x00FFFFFF;
  199.     if ((gmtOffset & 0x00800000) != 0) gmtOffset |= 0xFF000000;
  200.  
  201.     /* Try to parse the date we were passed. */
  202.     
  203.     secs = Parse822Date(date);
  204.     if (secs == 0) return;
  205.  
  206.     /* Correct for our timezone. */
  207.     
  208.     secs += gmtOffset;
  209.  
  210.     /* Convert it back into a Mac-style date/time string. */
  211.     
  212.     IUDateString(secs, abbrevDate, (StringPtr)date);
  213.     p2cstr((StringPtr)date);
  214.     strcat(date, " ");
  215.     IUTimeString(secs, true, time);
  216.     strcat(date, p2cstr(time));
  217. }
  218.  
  219.